package com.chen.time.timing.interpolation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class KeyValues<T> {

    private final List<T> values = new ArrayList<T>();
    private final Evaluator<T> evaluator;
    private final Class<?> type;
    private T startValue;

    public static <T> KeyValues<T> create(T... params) {
        return new KeyValues(params);
    }

    public static <T> KeyValues<T> create(Evaluator evaluator, T... params) {
        return new KeyValues(evaluator, params);
    }

    private KeyValues(T... params) {
        this(Evaluator.create(params.getClass().getComponentType()), params);
    }

    private KeyValues(Evaluator evaluator, T... params) {
        if (params == null) {
            throw new IllegalArgumentException("params array cannot be null");
        } else if (params.length == 0) {
            throw new IllegalArgumentException("params array must have at least one element");
        }
        if (params.length == 1) {
            // this is a "to" animation; set first element to null
            values.add(null);
        }
        Collections.addAll(values, params);
        this.type = params.getClass().getComponentType();
        this.evaluator = evaluator;
    }

    int getSize() {
        return values.size();
    }

    Class<?> getType() {
        return this.type;
    }

    void setStartValue(T startValue) {
        if (isToAnimation()) {
            this.startValue = startValue;
        }
    }

    boolean isToAnimation() {
        return values.get(0) == null;
    }

    T getValue(int i0, int i1, float fraction) {
        T value;
        T lowerValue = values.get(i0);
        if (lowerValue == null) {
            // "to" animation
            lowerValue = startValue;
        }
        if (i0 == i1) {
            // trivial case
            value = lowerValue;
        } else {
            T v0 = lowerValue;
            T v1 = values.get(i1);
            value = evaluator.evaluate(v0, v1, fraction);
        }
        return value;
    }
}
